#include "sfsis.h"
#include "effector.h"
#include "inAnimation.h"
#include "outAnimation.h"
#include "smelter_monochrome.h"
#include "smelter_rainbow.h"
#include "smelter_shuttle.h"
#include "smelter_breath.h"
#include "smelter_shading.h"
#include "smelter_blink.h"
#include "smelter_dot.h"
#include "smelter_screen.h"
#include "smelter_music.h"
#include "debug.h"
#include "helper.h"

/*效果编写规则
实现两个函数，restart和process

restart用于重启整个效果器的运动
process用于实现效果器的动画，注意每一帧必须都进行处理

需要注意process内不可修改配置，否则可能会有问题
process有几个返回值 
E_PROCESS 表明效果器正在执行
E_FINISHED 表明效果器不再执行了，此时会自动切换配置为设置的普通配置
*/
typedef enum
{
    ETS_IDEL,
    ETS_OUT,
    ETS_IN,
} Effector_TransState;

static Config_Mode_u TransitionMode;

Efct_Stage effector_modePorcess(Config_Mode *cfg)
{
    Efct_Stage ret = E_FINISHED;
    switch (cfg->mode)
    {
    case CONFIG_MODE_MONOCHROME:
        ret = smelter_monochrome_process(&cfg->context.monochrome);
        break;
    case CONFIG_MODE_RAINBOW:
        ret = smelter_rainbow_process(&cfg->context.rainbow);
        break;
    case CONFIG_MODE_BREATH:
        ret = smelter_breath_process(&cfg->context.breath);
        break;
    case CONFIG_MODE_SHUTTLE:
        ret = smelter_shuttle_process(&cfg->context.shuttle);
        break;
    case CONFIG_MODE_SHADING:
        ret = smelter_shading_process(&cfg->context.shading);
        break;
    case CONFIG_MODE_BLINK:
        ret = smelter_blink_process(&cfg->context.blink);
        break;
    case CONFIG_MODE_DOT:
        ret = smelter_dot_process(&cfg->context.dot);
        break;
    case CONFIG_MODE_SCREEN:
        ret = smelter_screen_process(&cfg->context.screen);
        break;
    case CONFOG_MODE_MUSIC:
        ret = smelter_music_process(&cfg->context.music);
        break;
    default:
        ret = smelter_monochrome_process(&cfg->context.monochrome);
        break;
    }
    return ret;
}

void effector_modeRestart(Config_Mode *cfg)
{
    Efct_Stage ret = E_FINISHED;
    switch (cfg->mode)
    {
    case CONFIG_MODE_MONOCHROME:
        smelter_monochrome_restart(&cfg->context.monochrome);
        break;
    case CONFIG_MODE_RAINBOW:
        smelter_rainbow_restart(&cfg->context.rainbow);
        break;
    case CONFIG_MODE_BREATH:
        smelter_breath_restart(&cfg->context.breath);
        break;
    case CONFIG_MODE_SHUTTLE:
        smelter_shuttle_restart(&cfg->context.shuttle);
        break;
    case CONFIG_MODE_SHADING:
        smelter_shading_restart(&cfg->context.shading);
        break;
    case CONFIG_MODE_BLINK:
        smelter_blink_restart(&cfg->context.blink);
        break;
    case CONFIG_MODE_DOT:
        smelter_dot_restart(&cfg->context.dot);
        break;
    case CONFIG_MODE_SCREEN:
        smelter_screen_restart(&cfg->context.screen);
        break;
    case CONFOG_MODE_MUSIC:
        smelter_music_restart(&cfg->context.music);
        break;
    default:
        smelter_monochrome_restart(&cfg->context.monochrome);
        break;
    }
}

void effector_init(void)
{
    su16 tmp = 0;
    for (tmp = 0; tmp < sizeof(Config_Mode_u); tmp++)
    {
        TransitionMode.memory[tmp] = gCfgPtr->mode.memory[tmp];
    }
    effector_modeRestart(&TransitionMode.entity);
}

void effector_setBrightness(su8 brightness)
{
    su16 tmp = 0;

    static Helper_EaseInEaseOut_Context context = {.key = 0, .target = 0};

    context.target = helper_cacl_precentage_denoinator255(brightness,gCfgFactoryPtr->maxBrightness);

    helper_easeInEaseOutGenerate(&context);

    for (tmp = 0; tmp < gCfgFactoryPtr->enabledDotNumber; tmp++)
    {
        rgbStrip.rgbMemory[tmp][0] = helper_cacl_precentage_denoinator255(rgbStrip.rgbMemory[tmp][0], context.key);
        rgbStrip.rgbMemory[tmp][1] = helper_cacl_precentage_denoinator255(rgbStrip.rgbMemory[tmp][1], context.key);
        rgbStrip.rgbMemory[tmp][2] = helper_cacl_precentage_denoinator255(rgbStrip.rgbMemory[tmp][2], context.key);
    }
}

void effector_clearNotEffectLeds(void)
{
    su16 tmp = 0;
    for (tmp = gCfgFactoryPtr->enabledDotNumber; tmp < 255; tmp++)
    {
        rgbStrip.rgbMemory[tmp][0] = 0;
        rgbStrip.rgbMemory[tmp][1] = 0;
        rgbStrip.rgbMemory[tmp][2] = 0;
    }
}

/*模式调度器,主要用于调度效果之间的切换和设置,它实现只有一个功能：不断的显示模式，并在模式间切换时，增加动画效果 */
void effector_modeswitch(void)
{
    static Effector_TransState ets = ETS_IN;
    switch (ets)
    {
    case ETS_IDEL:
        //当模式发生变化时，立即跳转至Fadeout,将当前模式渐隐
        if (TransitionMode.entity.mode != gCfgModePtr->mode)
        {
            outAnimationRestart(gCfgCommonPtr->outAnimationSelect);
            effector_modePorcess(&TransitionMode.entity);
            ets = ETS_OUT;
        }
        else
        {
            if (effector_modePorcess(gCfgModePtr) == E_FINISHED)
            {
                DPRINT(DEBUG_INFO, "[EFFECTOR] Current effect: %d finished, rest config to default.\r\n", gCfgModePtr->mode);
                config_restore(CONFIG_MODE);
                DPRINT(DEBUG_INFO, "[EFFECTOR] Restore to %d.\r\n", gCfgModePtr->mode);
            }
        }
        break;
    case ETS_OUT:
        //使用临时存储的效果器，直到当前模式完全隐藏
        effector_modePorcess(&TransitionMode.entity);
        if (outAnimation() == E_FINISHED)
        {
            su16 tmp = 0;
            for (tmp = 0; tmp < sizeof(Config_Mode_u); tmp++)
            {
                TransitionMode.memory[tmp] = gCfgPtr->mode.memory[tmp];
            }
            inAnimationRestart(gCfgCommonPtr->inAnimationSelect);
            effector_modeRestart(&TransitionMode.entity);
            ets = ETS_IN;
        }
        break;
    case ETS_IN:

        //渐隐完成后，使用临时存储的效果器，可以正常渐出了,这里仍然持续使用临时寄存器的原因是在动画过程中，可能用户又改了效果，这里要暂存，不能在动画时更改效果
        effector_modePorcess(&TransitionMode.entity);
        if (inAnimation() == E_FINISHED)
        {
            DPRINT(DEBUG_INFO, "[EFFECTOR] Effect: %d\r\n", TransitionMode.entity.mode);
            ets = ETS_IDEL;
        }
        break;
    default:
        break;
    }
}

/*根据灯光配置参数，对灯带做不同处理*/
void effector_task(void)
{
    if (gCfgCommonPtr->onOff == 0)
    {
        effector_setBrightness(0);
    }
    else
    {
        effector_modeswitch();
        effector_setBrightness(gCfgCommonPtr->brightness);
    }
    effector_clearNotEffectLeds();
}